package com.qianfan.invoice.service;

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import com.qianfan.invoice.config.QianfanProperties;

import com.qianfan.invoice.model.InvoiceResult;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Senhai Xu
 */

public class InvoiceOcrService {
    private final QianfanProperties properties;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public InvoiceOcrService(QianfanProperties properties) {
        this.properties = properties;
    }
    
    /**
     * 识别发票图片
     * @param imageBase64 图片base64编码
     * @return 发票识别结果
     */
    public InvoiceResult recognizeInvoice(String imageBase64) {
        try {
            // 1. 构建客户端
            OpenAIClient client = OpenAIOkHttpClient.builder()
                    .apiKey(properties.getApiKey())
                    .baseUrl(properties.getBaseUrl())
                    .build();

            // 2. 构造消息内容
            List<Map<String, Object>> contents = new ArrayList<>();
            
            // 添加图片内容
            Map<String, Object> imageUrlMap = new HashMap<>();
            imageUrlMap.put("url", imageBase64);
            
            Map<String, Object> imageContent = new HashMap<>();
            imageContent.put("type", "image_url");
            imageContent.put("image_url", imageUrlMap);
            contents.add(imageContent);
            
            // 添加文本内容
            Map<String, Object> textContent = new HashMap<>();
            textContent.put("type", "text");
            textContent.put("text",
                    "请分析这张发票的内容，并仅返回符合以下格式的JSON对象：\n" +
                            "{\n" +
                            "  \"invoiceCode\": \"发票代码\",\n" +
                            "  \"invoiceNumber\": \"发票号码\",\n" +
                            "  \"issueDate\": \"开票日期\",\n" +
                            "  \"totalAmount\": \"合计金额（不含税）\",\n" +
                            "  \"taxAmount\": \"税额\",\n" +
                            "  \"totalWithTax\": \"价税合计\",\n" +
                            "  \"purchaserName\": \"购买方名称\",\n" +
                            "  \"purchaserTaxNumber\": \"购买方纳税人识别号\",\n" +
                            "  \"sellerName\": \"销售方名称\",\n" +
                            "  \"sellerTaxNumber\": \"销售方纳税人识别号\"\n" +
                            "}\n\n" +
                            "注意事项：\n" +
                            "1. 必须严格遵循上述字段名和格式，不要添加额外字段\n" +
                            "2. 所有字段值必须用双引号包裹\n" +
                            "3. 日期格式建议使用YYYY-MM-DD\n" +
                            "4. 金额保留两位小数，格式为\"X.XX\"\n" +
                            "5. 如果某个字段无法识别，返回\"\"\n" +
                            "6. 不要包含任何解释或注释，仅返回JSON对象");
            contents.add(textContent);

            // 3. 构造消息
            Map<String, Object> message = new HashMap<>();
            message.put("role", "user");
            message.put("content", contents);

            // 4. 构造请求参数
            ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
                    .addSystemMessage("你是一个专业的发票识别助手。请严格按照要求的字段名称返回JSON格式的发票信息，确保每个字段的名称完全匹配，不要添加额外的字段。如果某个字段的信息无法识别，将其值设置为空字符串null。")
                    .putAdditionalBodyProperty("messages", JsonValue.from(List.of(message)))
                    .model(properties.getModel())
                    .temperature(properties.getTemperature())
                    .maxTokens(properties.getMaxTokens())
                    .build();

            // 5. 发送请求并处理响应
            ChatCompletion chatCompletion = client.chat().completions().create(params);
            String response = String.valueOf(chatCompletion.choices().get(0).message().content());
            
            return parseResponse(response);
        } catch (Exception e) {
            throw new RuntimeException("发票识别失败：" + e.getMessage(), e);
        }
    }
    
    /**
     * 解析API响应
     * @param response API响应文本
     * @return 发票识别结果
     */
    private InvoiceResult parseResponse(String response) {
        try {
            // 1. 移除Optional包装
            String cleanedResponse = response
                    .replaceAll("^Optional\\[", "")  // 移除开头的Optional[
                    .replaceAll("\\]$", "")          // 移除结尾的]
                    .trim();

            // 2. 提取第一个完整的JSON对象（处理额外文本的情况）
            String jsonStr = extractJsonContent(cleanedResponse);

            System.out.println("提取的JSON: " + jsonStr);

            // 3. 验证JSON格式
            if (!isValidJson(jsonStr)) {
                throw new IllegalArgumentException("解析失败：提取的内容不是有效的JSON对象");
            }

            // 4. 使用Jackson进行严格映射，忽略未知字段
            InvoiceResult result = objectMapper.readValue(jsonStr, InvoiceResult.class);
            // 保存原始响应用于调试
            result.setRawResponse(response);
            return result;
        } catch (Exception e) {
            System.out.println("解析发票响应失败: {}"+e.getMessage()+ e);
            throw new RuntimeException("解析发票响应失败", e);
        }
    }

    /**
     * 从文本中提取第一个完整的JSON对象
     */
    private String extractJsonContent(String text) {
        // 查找第一个左大括号
        int startIndex = text.indexOf("{");
        if (startIndex == -1) {
            throw new IllegalArgumentException("未找到有效的JSON对象起始标记");
        }

        // 使用栈来查找匹配的右大括号
        int braceCount = 0;
        int endIndex = -1;

        for (int i = startIndex; i < text.length(); i++) {
            char c = text.charAt(i);
            if (c == '{') {
                braceCount++;
            }
            if (c == '}') {
                braceCount--;
            }

            if (braceCount == 0) {
                endIndex = i;
                break;
            }
        }

        if (endIndex == -1 || braceCount != 0) {
            throw new IllegalArgumentException("未找到匹配的JSON对象结束标记");
        }

        return text.substring(startIndex, endIndex + 1);
    }

    /**
     * 简单验证是否是有效的JSON对象
     */
    private boolean isValidJson(String json) {
        json = json.trim();
        return json.startsWith("{") && json.endsWith("}");
    }
} 